﻿
Imports std

'need a locked_slice_wrapper to be around
Public Class cached_slice_wrapper
    Inherits slice_wrapper

    Private Class cache
        Private Const cacheticks As Int64 = cacheManager(Of String, bytes).notRetireTicks
        Private Const cache_count As Int64 = 32768
        Private Const cache_size As Int64 = 1024
        Private ReadOnly value As cacheManager(Of String, pair(Of pointer(Of bytes), Int64)) = Nothing

        Public Sub New()
            value = New cacheManager(Of String, pair(Of pointer(Of bytes), Int64))(False, cache_count, cacheticks)
        End Sub

        Public Sub [erase](ByVal key As String)
            assert(Not isemptystring(key))
            value.erase(key)
        End Sub

        Public Sub clear()
            value.clear()
        End Sub

        Public Function existing(ByVal key As String) As Boolean
            Return value.have(key)
        End Function

        Public Sub set_value(ByVal key As String, ByVal b As bytes, ByVal ts As Int64)
            assert(Not isemptystring(key))
            assert(Not b Is Nothing)
            assert(ts > 0)
            If b.size() <= cache_size Then
                value.add(key, make_pair(New pointer(Of bytes)(copy(b)), ts))
            Else
                [erase](key)
            End If
        End Sub

        Public Function get_value(ByVal key As String, ByRef v As bytes, ByRef ts As Int64) As Boolean
            assert(Not isemptystring(key))
            Dim p As pair(Of pointer(Of bytes), Int64) = Nothing
            If value.get(key, p) Then
                v = +(p.first)
                ts = p.second
                Return True
            Else
                Return False
            End If
        End Function
    End Class

    Private ReadOnly c As cache = Nothing

    Public Sub New(ByVal s As islice)
        MyBase.New(s)
        c = New cache()
    End Sub

    Private Shared Function eva(Of T)(ByVal p As pointer(Of T), ByVal v As T) As Boolean
        Global.eva(p, v)
        Return True
    End Function

    Private Overloads Shared Function workon(ByVal d As _do(Of pointer(Of Boolean), eventComb),
                                             ByVal f As _do(Of Boolean, Boolean)) As eventComb
        assert(Not f Is Nothing)
        Return workon(d,
                      Function(ByRef r As Boolean, ByRef i As Boolean) As Boolean
                          Return f(r AndAlso i)
                      End Function)
    End Function

    Private Overloads Shared Function workon(Of T)(ByVal d As _do(Of pointer(Of T), eventComb),
                                                   ByVal f As _do(Of Boolean, T, Boolean)) As eventComb
        assert(Not d Is Nothing)
        assert(Not f Is Nothing)
        Return workon(Function(ByRef p1 As pointer(Of T), ByRef p2 As pointer(Of Byte)) As eventComb
                          Return d(p1)
                      End Function,
                      Function(ByRef r As Boolean, ByRef i As T, ByRef n As Byte) As Boolean
                          Return f(r, i)
                      End Function)
    End Function

    Private Overloads Shared Function workon(Of T1, T2)(ByVal d As _do(Of pointer(Of T1), pointer(Of T2), eventComb),
                                                        ByVal f As _do(Of Boolean, T1, T2, Boolean)) As eventComb
        assert(Not d Is Nothing)
        assert(Not f Is Nothing)
        Dim ec As eventComb = Nothing
        Dim p1 As pointer(Of T1) = Nothing
        Dim p2 As pointer(Of T2) = Nothing
        Return New eventComb(Function() As Boolean
                                 p1 = New pointer(Of T1)()
                                 p2 = New pointer(Of T2)()
                                 ec = d(p1, p2)
                                 Return (ec Is Nothing AndAlso goto_end()) OrElse
                                        (waitfor(ec) AndAlso goto_next())
                             End Function,
                             Function() As Boolean
                                 assert(Not ec Is Nothing)
                                 Return f(ec.end_result(), +p1, +p2) AndAlso
                                        ec.end_result() AndAlso
                                        goto_end()
                             End Function)
    End Function

    Public Overrides Function delete(ByVal key As String,
                                     ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(Function(ByRef p As pointer(Of Boolean)) As eventComb
                          Return slice.delete(key, p)
                      End Function,
                      Function(ByRef r As Boolean) As Boolean
                          If r Then
                              c.erase(key)
                          End If
                          Return eva(result, r)
                      End Function)
    End Function

    Private Delegate Function mu_delegate(ByVal key As String,
                                          ByVal buff As bytes,
                                          ByVal ts As Int64,
                                          ByVal result As pointer(Of Boolean)) As eventComb

    Private Function mu(ByVal key As String,
                        ByVal buff As bytes,
                        ByVal ts As Int64,
                        ByVal result As pointer(Of Boolean),
                        ByVal mud As mu_delegate) As eventComb
        assert(Not mud Is Nothing)
        Return workon(Function(ByRef p As pointer(Of Boolean)) As eventComb
                          Return mud(key, buff, ts, p)
                      End Function,
                      Function(ByRef r As Boolean) As Boolean
                          If r Then
                              c.set_value(key, buff, ts)
                          End If
                          Return eva(result, r)
                      End Function)
    End Function

    Public Overrides Function modify(ByVal key As String,
                                     ByVal buff As bytes,
                                     ByVal ts As Int64,
                                     ByVal result As pointer(Of Boolean)) As eventComb
        Return mu(key, buff, ts, result, AddressOf slice.modify)
    End Function

    Public Overrides Function read(ByVal key As String,
                                   ByVal result As pointer(Of bytes),
                                   ByVal ts As pointer(Of Int64)) As eventComb
        Return workon(Function(ByRef p1 As pointer(Of bytes), ByRef p2 As pointer(Of Int64)) As eventComb
                          Dim v As bytes = Nothing
                          Dim t As Int64 = 0
                          If c.get_value(key, v, t) Then
                              assert(eva(result, v))
                              assert(eva(ts, t))
                              Return Nothing
                          Else
                              Return slice.read(key, p1, p2)
                          End If
                      End Function,
                      Function(ByRef r As Boolean, ByRef p1 As bytes, ByRef p2 As Int64) As Boolean
                          If r AndAlso Not p1 Is Nothing AndAlso p2 > 0 Then
                              c.set_value(key, p1, p2)
                              Return eva(result, p1) AndAlso eva(ts, p2)
                          Else
                              Return eva(result, Nothing) AndAlso eva(ts, npos)
                          End If
                      End Function)
    End Function

    Public Overrides Function retire(ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(Function(ByRef p As pointer(Of Boolean)) As eventComb
                          Return slice.retire(p)
                      End Function,
                      Function(ByRef r As Boolean) As Boolean
                          If r Then
                              c.clear()
                          End If
                          Return eva(result, r)
                      End Function)
    End Function

    Public Overrides Function seek(ByVal key As String,
                                   ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(Function(ByRef p As pointer(Of Boolean)) As eventComb
                          If c.existing(key) Then
                              assert(eva(result, True))
                              Return Nothing
                          Else
                              Return slice.seek(key, p)
                          End If
                      End Function,
                      Function(ByRef r As Boolean) As Boolean
                          Return eva(result, r)
                      End Function)
    End Function

    Public Overrides Function sizeof(ByVal key As String,
                                     ByVal result As pointer(Of Int64)) As eventComb
        Return workon(Function(ByRef p As pointer(Of Int64)) As eventComb
                          Dim b As bytes = Nothing
                          If c.get_value(key, b, Nothing) Then
                              assert(eva(result, b.size()))
                              Return Nothing
                          Else
                              Return slice.sizeof(key, p)
                          End If
                      End Function,
                      Function(ByRef r As Boolean, ByRef i As Int64) As Boolean
                          If r Then
                              Return eva(result, i)
                          Else
                              Return eva(result, npos)
                          End If
                      End Function)
    End Function

    Public Overrides Function uniqueWrite(ByVal key As String,
                                          ByVal buff As bytes,
                                          ByVal ts As Int64,
                                          ByVal result As pointer(Of Boolean)) As eventComb
        Return mu(key, buff, ts, result, AddressOf slice.uniqueWrite)
    End Function

    Public Overrides Function write(ByVal key As String,
                                    ByVal buff As bytes,
                                    ByVal ts As Int64,
                                    ByVal result As pointer(Of Boolean)) As eventComb
        Return workon(Function(ByRef p As pointer(Of Boolean)) As eventComb
                          Return slice.write(key, buff, ts, p)
                      End Function,
                      Function(ByRef r As Boolean) As Boolean
                          If r Then
                              Dim b As bytes = Nothing
                              If c.get_value(key, b, Nothing) Then
                                  c.set_value(key, b + buff, ts)
                              End If
                          End If
                          Return eva(result, r)
                      End Function)
    End Function
End Class
